//
//  APIResult.swift
//  Casecord
//
//  Created by baozi on 2024/1/3.
//

import Foundation
import RxSwift
import SwiftyJSON
import HandyJSON
// MARK: - 主数据，网络请求最先返回的数据
enum UnWrapMainKey {
    case ext
    case result
}

struct APIExt: HandyJSON {
    /// 充值金币
    var rechargeCoin: Int?
    /// 赠送钻石
    var sendRechargeCoin: Int64?
    /// 总金币
    var gainCoin: Int64?
    /// 今天的免费次数
    var todayFreeCallCount: Int?
}

struct APIResult: Codable {
    var code : Int?
    var hasError: Bool?
    var timestamp: Int64?
    var errorMsg: String?
    var errorCode: Int?
    var ext: JSON?
    var result : JSON?
    
    enum CodingKeys: String, CodingKey {
        case code
        case result
        case hasError
        case timestamp
        case errorMsg
        case errorCode
        case ext
    }
    
    init() {}
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        code = try? container.decodeIfPresent(Int.self, forKey: .code)
        hasError = try? container.decodeIfPresent(Bool.self, forKey: .hasError)
        timestamp = try? container.decodeIfPresent(Int64.self, forKey: .timestamp)
        errorMsg = try? container.decodeIfPresent(String.self, forKey: .errorMsg)
        errorCode = try? container.decodeIfPresent(Int.self, forKey: .errorCode)
        result = try? container.decodeIfPresent(JSON.self, forKey: .result)
        ext = try? container.decodeIfPresent(JSON.self, forKey: .ext)
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try? container.encodeIfPresent(self.code, forKey: .code)
        try? container.encodeIfPresent(self.result, forKey: .result)
        try? container.encodeIfPresent(self.hasError, forKey: .hasError)
        try? container.encodeIfPresent(self.timestamp, forKey: .timestamp)
        try? container.encodeIfPresent(self.errorMsg, forKey: .errorMsg)
        try? container.encodeIfPresent(self.errorCode, forKey: .errorCode)
        try? container.encodeIfPresent(self.ext, forKey: .ext)
    }
    
    /// 解析HandyJSON类型数据
    func unwrap<T: HandyJSON>(type: T.Type, key: UnWrapMainKey =  .result, obj: Any? = nil) -> T? {
        var dict: [String: Any]?
        if let obj = obj {
            dict = obj as? [String: Any]
        } else if key == .result {
            dict = result?.dictionaryObject
        } else if key == .ext {
            dict = ext?.dictionaryObject
        }
        guard let dict = dict else { return nil }
        let v = T.deserialize(from: dict)
        return v
    }
    
    /// HandyJSON解包纯数组
    func unwrapList<T: HandyJSON>(type: T.Type, key: UnWrapMainKey =  .result, obj: Any? = nil) -> [T]? {
        var dict: [[String: Any]]?
        if let obj = obj {
            dict = obj as? [[String: Any]]
        } else if key == .result {
            dict = result?.arrayObject as? [[String: Any]]
        } else if key == .ext {
            dict = ext?.arrayObject as? [[String: Any]]
        }
        guard let dict = dict else { return nil }
        let list = dict.compactMap { json in
            return self.unwrap(type: T.self, obj: json)
        }
        return list
    }
    
    func unwrap<T: Codable>(type: T.Type, key: UnWrapMainKey = .result, obj: Any? = nil) -> T? {
        var dict: [String: Any]?
        if let obj = obj {
            dict = obj as? [String: Any]
        } else if key == .result {
            dict = result?.dictionaryObject
        } else if key == .ext {
            dict = ext?.dictionaryObject
        }
        guard let dict = dict,
              let data = try? JSONSerialization.data(withJSONObject: dict),
              let m = try? JSONDecoder().decode(T.self, from: data)
        else {
            return nil
        }
        return m
    }
    // zsaResult为数组
    func unwrapList<T: Codable>(type: T.Type, key: UnWrapMainKey = .result, obj: Any? = nil) -> [T]? {
        var dict: [[String: Any]]?
        if let obj = obj {
            dict = obj as? [[String: Any]]
        } else if key == .result {
            dict = result?.arrayObject as? [[String: Any]]
        } else if key == .ext {
            dict = ext?.arrayObject as? [[String: Any]]
        }
        guard let dict = dict else { return nil }
        let list = dict.compactMap { json in
            return self.unwrap(type: T.self, obj: json)
        }
        return list
    }
    
}

extension PrimitiveSequence where Trait == SingleTrait, Element == APIResult {
    
    /// 解析HandyJSON类型数据
    func unwrap<T: HandyJSON>(type: T.Type, key: UnWrapMainKey =  .result, obj: Any? = nil) -> Single<T> {
        map { e -> T in
            if let t = e.unwrap(type: T.self) {
                return t
            } else {
                throw APIError.jsonDataError
            }
        }
    }
    
    /// HandyJSON解包纯数组
    func unwrapList<T: HandyJSON>(type: T.Type, key: UnWrapMainKey =  .result, obj: Any? = nil) -> Single<[T]> {
        map { e -> [T] in
            if let t = e.unwrapList(type: T.self, key: key, obj: obj) {
                return t
            } else {
                throw APIError.jsonDataError
            }
        }
    }
    
    func unwrap<T: Codable>(type: T.Type, key: UnWrapMainKey = .result, obj: Any? = nil) -> Single<T> {
        map { e -> T in
            if let t = e.unwrap(type: T.self) {
                return t
            } else {
                throw APIError.jsonDataError
            }
        }
    }
    // zsaResult为数组
    func unwrapList<T: Codable>(type: T.Type, key: UnWrapMainKey = .result, obj: Any? = nil) -> Single<[T]> {
        map { e -> [T] in
            if let t =  e.unwrapList(type: T.self, key: key, obj: obj) {
                return t
            } else {
                throw APIError.jsonDataError
            }
        }
    }
}

